﻿using System.Collections.Generic;
using System.Text;
using System.Web.Mvc;
using System.Web.Routing;

namespace RecaptchaMvc {
	public static class HtmlExtensions {
		private const string _nonSecureUrl = "http://api.recaptcha.net/";
		private const string _secureUrl = "https://api-secure.recaptcha.net/";

		private static string Options(IDictionary<string, object> options) {
			if((options == null) || (options.Count == 0))
				return string.Empty;
			StringBuilder html = new StringBuilder("var RecaptchaOptions = {");
			foreach(KeyValuePair<string, object> pair in options) {
				html.Append(pair.Key);
				html.Append(": ");
				if(pair.Value is string)
					html.Append("\"");
				html.Append(pair.Value);
				if(pair.Value is string)
					html.Append("\"");
			}
			TagBuilder builder = new TagBuilder("script");
			builder.InnerHtml = html.ToString();
			builder.Attributes["type"] = "text/javascript";
			return builder.ToString(TagRenderMode.Normal);
		}
		private static string NoScript(IRecaptchaModelState state, bool isSecure) {
			TagBuilder builder = new TagBuilder("object");
			builder.Attributes["data"] = HtmlExtensions.Url(state, true, isSecure);
			builder.Attributes["type"] = "text/html";
			StringBuilder html = new StringBuilder(builder.ToString(TagRenderMode.Normal));
			builder = new TagBuilder("textarea");
			builder.Attributes["name"] = "recaptcha_challenge_field";
			builder.Attributes["rows"] = "3";
			builder.Attributes["cols"] = "40";
			html.Append(builder.ToString(TagRenderMode.Normal));
			builder = new TagBuilder("input");
			builder.Attributes["name"] = "recaptcha_response_field";
			builder.Attributes["type"] = "hidden";
			builder.Attributes["value"] = "manual_challenge";
			html.Append(builder.ToString(TagRenderMode.SelfClosing));
			builder = new TagBuilder("div");
			builder.InnerHtml = html.ToString();
			builder.Attributes["class"] = "recaptcha";
			TagBuilder noscriptBuilder = new TagBuilder("noscript");
			noscriptBuilder.InnerHtml = builder.ToString(TagRenderMode.Normal);
			return noscriptBuilder.ToString(TagRenderMode.Normal);
		}
		public static string Recaptcha(this HtmlHelper helper, IRecaptchaModelState state) {
			return helper.Recaptcha(state, (IDictionary<string, object>)null);
		}
		public static string Recaptcha(this HtmlHelper helper, IRecaptchaModelState state, object options) {
			return helper.Recaptcha(state, (IDictionary<string, object>)new RouteValueDictionary(options));
		}
		public static string Recaptcha(this HtmlHelper helper, IRecaptchaModelState state, IDictionary<string, object> options) {
			StringBuilder builder = new StringBuilder();
			builder.Append(HtmlExtensions.Options(options));
			bool isSecure = helper.ViewContext.HttpContext.Request.IsSecureConnection;
			builder.Append(HtmlExtensions.Script(state, isSecure));
			builder.Append(HtmlExtensions.NoScript(state, isSecure));
			return builder.ToString();
		}
		private static string Script(IRecaptchaModelState state, bool isSecure) {
			TagBuilder builder = new TagBuilder("script");
			builder.Attributes["type"] = "text/javascript";
			builder.Attributes["src"] = HtmlExtensions.Url(state, false, isSecure);
			return builder.ToString(TagRenderMode.Normal);
		}
		private static string Url(IRecaptchaModelState state, bool noScript, bool isSecure) {
			StringBuilder builder = new StringBuilder();
			builder.Append(isSecure ? HtmlExtensions._secureUrl : HtmlExtensions._nonSecureUrl);
			builder.Append(noScript ? "noscript" : "challenge");
			builder.Append("?k=");
			builder.Append(state.PublicKey);
			if(!string.IsNullOrEmpty(state.ErrorCode)) {
				builder.Append("&error=");
				builder.Append(state.ErrorCode);
			}
			return builder.ToString();
		}
	}
}